#ifndef BAS_BAS_HASH_MAP_H
#define BAS_BAS_HASH_MAP_H

#include "bas/bas_const.h"
#include "bas/bas_iterator.h"

/**
 * 哈希函数
 */
typedef unsigned int (*T_HashFunction)(const void *, const size_t);

/**
 * @brief     默认哈希函数
 * @param[in] pvKey      关键字
 * @param[in] nKeyLength 关键字长度
 * @returns   根据关键字计算得到的哈希值
 */
unsigned int basHashMapDefaultHash(const void *pvKey, const size_t nKeyLength);

#include "bas/bas_hash_map_private.h"

/**
 * @brief     创建一个哈希映射 
 * @param[in] tKeyTypeInfo   关键字的类型信息
 * @param[in] tValueTypeInfo 值的类型信息
 * @param[in] pfnHash        可选参数为用户指定的哈希函数指针, 类型为T_HashFunction
 * @returns   指向哈希映射的指针, 创建失败返回NULL
 * @note      1.使用_T()宏来得到类型信息，具体可以查看_T()宏的文档
 *            2.关键字类型的自定义函数都被忽略(比如拷贝函数，销毁函数等), 关键字在容器中只存放浅拷贝
 *            samples:
 *                1.内置字符串作为关键字, T_YourStruct类型作为值
 *                  T_HashMap *ptHashMap = basHashMapCreate(_T(BUILDIN_STRING), _T(T_YourStruct));
 *                2.T_YourStruct1类型作为关键字, T_YourStruct2类型作为值, 同时制定销毁函数
 *                  T_HashMap *ptHashMap = basHashMapCreate(_T(T_YourStruct1), _T(T_YourStruct2, pfnDestroy));
 *                3.内置字符串作为关键字, T_YourStruct类型作为值, 同时指定用户定义的哈希函数
 *                  T_HashMap *ptHashMap = basHashMapCreate(_T(BUILDIN_STRING), _T(T_YourStruct), pfnHash);
 */
#define basHashMapCreate(_tKeyTypeInfo, _tValueTypeInfo, ...) _basHashMapCreate(_tKeyTypeInfo, _tValueTypeInfo, ##__VA_ARGS__, BAS_PARM_END)

/**
 * @brief     销毁哈希映射
 * @param[in] ptHashMap 指向HashMap的指针
 */
void basHashMapDestroy(T_HashMap *ptHashMap);

/**
 * @brief    清空哈希映射, 删除其中所有的键值对
 * @param[in] ptHashMap 指向HashMap的指针
 */
void basHashMapClear(T_HashMap *ptHashMap);

/**
 * @brief     返回哈希映射中存放的键值对个数 
 * @param[in] ptHashMap 指向HashMap的指针
 * @returns   哈希映射中存放的键值对个数
 */
size_t basHashMapSize(const T_HashMap *ptHashMap);

/**
 * @brief     测试哈希映射是否为空
 * @param[in] ptHashMap 指向HashMap的指针
 * @returns   true - Vector为空　false - Vector不为空
 */
bool basHashMapEmpty(const T_HashMap *ptHashMap);

/**
 * @brief     向哈希映射中插入一个键值对
 * @param[in] ptHashMap 指向HashMap的指针
 * @param[in] key       关键字, 对于内置类型, 该参数为内置类型本身, 对于用户定义的结构体类型,该参数为结构体指针
 * @param[in] value     值, 对于内置类型, 该参数为内置类型本身, 对于用户定义的结构体类型,该参数为结构体指针
 * @returns   0 - 成功 -1 - 失败
 * @note      1.如果值指定了拷贝函数, 则调用拷贝函数, 执行深拷贝, 请注意复杂类型导致的内存泄漏
 *            2.如果插入时发现HashMap中已经有了相同关键字的键值对, 则先将原先的键值对删除, 再插入新的键值对,
 *              同时对旧的值类型调用销毁函数(如果有的话)
 * @warning   该操作可能使得之前basHashMapFind得到的指针失效, 也可能使得之前得到的所有迭代器失效
 */
int basHashMapInsert(T_HashMap *ptHashMap, ...);

/**
 * @brief     清除在哈希映射中指定关键字的键值对 
 * @param[in] ptHashMap 指向HashMap的指针
 * @param[in] key       关键字, 对于内置类型, 该参数为内置类型本身, 对于用户定义的结构体类型,该参数为结构体指针
 * @returns   0 - 成功 -1 - 失败(没有该关键字的键值对)
 * @warning   该操作使得指向该键值对的迭代器失效
 */
int basHashMapErase(T_HashMap *ptHashMap, ...);

/**
 * @brief     根据关键字在哈希映射中寻找值
 * @param[in] ptHashMap 指向HashMap的指针
 * @param[in] key       关键字, 对于内置类型, 该参数为内置类型本身, 对于用户定义的结构体类型,该参数为结构体指针
 * @returns   返回指向值数据的指针, 没有找到返回NULL, 特别要注意BUILDIN_STRING类型, 返回值是(char *)的指针, 也就是(char **),
 * @warning   修改BUILDIN_STRING类型的返回值时, 请注意不能改变字符串长度, 否则将导致内存越界或者内存泄露
 */
void *basHashMapFind(const T_HashMap *ptHashMap, ...);

/**
 * @brief     返回指向哈希映射第一个键值对的迭代器, 类型为输入迭代器
 * @param[in] ptHashMap 指向HashMap的指针
 * @returns   指向哈希映射第一个元素的迭代器
 */
T_Iterator basHashMapBegin(const T_HashMap *ptHashMap);

/**
 * @brief     返回指向哈希映射末尾(最后一个键值对之后)的迭代器(哨兵迭代器), 类型为输入迭代器
 * @param[in] ptHashMap 指向HashMap的指针
 * @returns   指向哈希映射末尾的迭代器
 */
T_Iterator basHashMapEnd(const T_HashMap *ptHashMap);

#endif
